package com.zrz.util;

import com.google.common.base.Joiner;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.util.Base64;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @since 2017/09/07  11:41
 */
public class WxUtils {

    public final static String WX_JSCODE2SESSION = "https://api.weixin.qq.com/sns/jscode2session";
    public final static String WX_GETWXACODEUNLIMIT = "https://api.weixin.qq.com/wxa/getwxacodeunlimit";
    public final static String WX_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    public final static String WX_UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    // 概况趋势
    public final static String WX_DAILY_VISITED = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend";

    public final static String RETURN_CODE_SUCCESS = "SUCCESS";
    public final static String RETURN_CODE_FAIL = "FAIL";


    public final static String APP_ID = "wxe0bd118fa5a91d7f";
    public final static String MCH_ID = "1519431451";
    public final static String NOTIFY_URL ="https://wechat.uwetech.cn/wechart/rechargeNotify";
//    public final static String NOTIFY_URL ="https://portapi.zaiyicaifu.com/api/user/rechargeNotify";
    public final static String KEY = "aaaaaaaabbbbbbbb8888888866666666";

    private static LoadingCache<String, String> TOKEN_CACHE = CacheBuilder.newBuilder().maximumSize(1000)
            .expireAfterWrite(7000, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                       public String load(String key) throws InterruptedException {
                           return newAccessToken();
                       }
            }
    );

    private WxUtils() {

    }

    private static String newAccessToken() {
        String requestUrl = String.format(WX_TOKEN, "wx4e6bcad7b788b6f8","940471bc4de3d29e0f4d7bf47a839461");
        String bodyText = HttpRequest.get(requestUrl).send().body();
        JSONObject body = JSONObject.fromObject(bodyText);
        if (body.has("access_token")) {
            String accessToken = body.getString("access_token");
            Integer expiresIn = body.getInt("expires_in");
            return accessToken;
        }
        return null;
    }


    public static String accessToken() {
        try {
            String accessToken = TOKEN_CACHE.get("token");
            return accessToken;
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return "";
    }

    private static Element newElement(String name,String value){
        return DocumentHelper.createElement(name).addText(value);
    }

    private static String getXml(TreeMap<String,String> body){
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("xml");// 创建根节点
        body.forEach((k,v)->{
            root.add(newElement(k,v));
        });
        return root.asXML();
    }


    private static TreeMap<String, String> unifiedOrderData(String openId, String tradeNo, String ip, BigDecimal totalFee, String attach,Integer type) {
        TreeMap<String, String> body = Maps.newTreeMap();
        body.put("appid", APP_ID);
        body.put("attach", type+"");
        body.put("body", "JSAPI支付");
        body.put("mch_id", MCH_ID);
        body.put("detail", attach);
        String nonceStr = ToolUtils.randomStr(20);
        body.put("nonce_str", nonceStr);
        body.put("notify_url", NOTIFY_URL);
        body.put("openid", openId);
        body.put("out_trade_no", tradeNo);
        body.put("spbill_create_ip", ip);
        body.put("total_fee", String.valueOf(totalFee.multiply(new BigDecimal(100)).longValue()));
        body.put("trade_type", "JSAPI");
        body.put("sign", signByMd5(body));
        return body;
    }




    public static HashMap<String,String> unifiedOrder(String openId, String tradeNo, String ip, BigDecimal totalFee, String detail,Integer type) {
        HttpResponse httpResponse = HttpRequest.post(WX_UNIFIEDORDER)
                .bodyText(getXml(unifiedOrderData(openId, tradeNo, ip, totalFee, detail,type))).charset("utf-8").send();
        try {
            String result = new String(httpResponse.bodyBytes(), "utf-8");
            return ToolUtils.xml2Map(result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static final String signByMd5(TreeMap<String, String> body) {
        List<String> waitList = Lists.newArrayList();
        body.forEach((k, v) -> {
            waitList.add(k + "=" + v);
        });
        waitList.add("key=" + KEY);
        String waitStr = Joiner.on("&").join(waitList);
        LogUtils.info("waitStr===="+waitStr);
        String sign = MD5Util.MD5(waitStr).toUpperCase();
        return sign;
    }


    public static String payRes(String returnCode, String returnMsg) {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("xml");// 创建根节点
        root.add(newElement("return_code", returnCode));
        root.add(newElement("return_msg", returnMsg));
        return root.asXML();
    }




    public static String getMobile(String sessionKeyStr,String encryptedDataStr,String ivStr){
        byte[] sessionKey = Base64.decode(sessionKeyStr);
        byte[] encryptedData = Base64.decode(encryptedDataStr);
        byte[] iv = Base64.decode(ivStr);
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
            byte[] result = cipher.doFinal(encryptedData);
            String value = new String(result, "utf-8");
            JSONObject jsonObject = JSONObject.fromObject(value);
            if(jsonObject.has("purePhoneNumber")){
                return jsonObject.getString("purePhoneNumber");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
